import numpy
glo = 0
ghi = 94 * 8
np = 12

nlev = 7
maxlev = 7
glen = ghi - glo
llen = (ghi - glo) / np
cutoff = 12
skin = 2
order = 4
maxcomm = numpy.zeros(maxlev, dtype=numpy.int)
nproc = numpy.zeros(maxlev, dtype=numpy.int)
delinv = numpy.zeros(maxlev)
nmsm = numpy.zeros(maxlev, dtype=numpy.int)
nmsm_proc = numpy.zeros(maxlev, dtype=numpy.int)
get_llo = lambda p: llen * p + glo
get_lhi = lambda p: llen * (p + 1) + glo
ifloor = lambda x: int(numpy.floor(x))
get_nlo = lambda nm, np, p: p * ifloor(nm / np) + min(p, nm % np)
get_nhi = lambda nm, np, p: get_nlo(nm, np, p + 1) - 1
grid_for_restrict= lambda nlo, nhi, delinv, i: [nlo * delinv[i - 1] / delinv[i] - order + 1, nhi * delinv[i - 1] / delinv[i] + order - 1]
grid_for_direct = lambda nlo, nhi, delinv, i: [nlo - ndirect, nhi + ndirect]
grid_for_prolong = lambda nlo, nhi, delinv, i: [(nlo - order + 1) * delinv[i + 1] / delinv[i], (nhi + order - 1) * delinv[i + 1] / delinv[i]]
for p in range(np):
  for i in range(maxlev):
    nmsm[i] = int(2 ** (nlev - i))
    if nmsm[i] == 0:
      nmsm[i] = 1
    delinv[i] = nmsm[i] / glen
  ndirect = (2 * cutoff * delinv[0])
  halo = max(order, ndirect)
  #sizeof q0 in reverse comm requires n
  nlo_in, nhi_in = [numpy.zeros(maxlev, dtype=numpy.int) for i in range(2)]
  nlo_out = numpy.zeros(maxlev, dtype=numpy.int) + 0x3fffffff
  nhi_out = numpy.zeros(maxlev, dtype=numpy.int) - 0x3fffffff
  nlo_req = numpy.zeros(maxlev, dtype=numpy.int) + 0x3fffffff
  nhi_req = numpy.zeros(maxlev, dtype=numpy.int) - 0x3fffffff
  nlo_out[0] = ifloor((get_llo(p) - skin * 0.5 - glo) * delinv[0]) - halo
  nhi_out[0] = ifloor((get_lhi(p) + skin * 0.5 - glo) * delinv[0]) - 1 + halo
  nlo_in[0] = ifloor((get_llo(p) - glo) * delinv[0])
  nhi_in[0] = ifloor((get_lhi(p) - glo) * delinv[0]) - 1
  maxcomm[0] = 5#max(nlo_in[0] - nlo_out0, nhi_out0 - nhi_in[0])
  #print(maxcomm[0])
  maxcomm[1:] = halo
  nproc[0] = np
  for i in range(1, maxlev):
    nproc[i] = min(max(ifloor(nmsm[i] / maxcomm[i]), 1), np)
    #nmsm_proc[i] = nmsm[i] / nproc[i]
    if (p < nproc[i]):
      nlo_in[i] = get_nlo(nmsm[i], nproc[i], p)
      nhi_in[i] = get_nhi(nmsm[i], nproc[i], p)
      
      #print(p, i, nlo_in[i], nhi_in[i])
      nlo_req[i - 1] = nlo_in[i] * delinv[i - 1] / delinv[i] - halo
      nhi_req[i - 1] = nhi_in[i] * delinv[i - 1] / delinv[i] + halo
      nlo_out[i] = nlo_in[i] - halo
      nhi_out[i] = nhi_in[i] + halo
  # print(p, list(zip(nlo_req, nlo_out, nlo_in, nhi_in, nhi_out, nhi_req)))
  print('%d:' % p)
  for i in range(0, maxlev):
    print(nproc[i])
    if p < nproc[i]:
      if (i > 0 and nproc[i] < nproc[i - 1]):
        grlo, grhi = grid_for_restrict(nlo_in[i], nhi_in[i], delinv, i)
        print('gather qgrid %d[%d : %d]' % (i - 1, grlo, grhi))
      print('compute qgrid %d[%d : %d]' % (i, nlo_in[i], nhi_in[i]))
      if nproc[i] != 1:
        lo_nxt, hi_nxt = get_nlo(nmsm[i + 1], nproc[i + 1], p + 1), get_nhi(nmsm[i + 1], nproc[i + 1], p + 1)
        grlo_nxt, grhi_nxt = grid_for_restrict(lo_nxt, hi_nxt, delinv, i + 1)
        print(lo_nxt, hi_nxt, grlo_nxt, grhi_nxt)
    else:
      if p < nproc[i - 1]:
        print('sendout qgrid')
  for i in range(maxlev - 1, -1, -1):
    if p < nproc[i]:
      if (i < maxlev - 1 and p >= nproc[i + 1]):
        gdlo, gdhi = grid_for_direct(nlo_in[i], nhi_in[i], delinv, i)
        print('receive qgrid %d[%d : %d]' % (i, gdlo, gdhi))
        gplo, gphi = grid_for_prolong(nlo_in[i], nhi_in[i], delinv, i)
        #print(nlo, (nlo - order + 1), delinv[i] / delinv[i + 1])
        print('receive egrid %d[%d : %d]' % (i, gplo, gphi))
        print(grid_for_restrict(gphi, gplo, delinv, i + 1))
      print('compute egrid %d[%d : %d]' % (i, nlo_in[i], nhi_in[i]))